#include "Timer.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;

#define PRECISION double

void Convolve(PRECISION * pInput, PRECISION * pFilter, PRECISION * pOutput,
 		 int nInputWidth, int nWidth, int nHeight, 
 		 int nFilterWidth);//nWidth = Input Width (Cols1), nFilterWidth = Width of Filter (cols2), nHeight = Height of the Filter and the Input(rows1 and rows2), nWidth= Length of the Filter and the Input(cols1 and cols2)

int random_value1;
int random_value2;
int nInputWidth, nFilterWidth;//equivalent to Cols1 and Cols2
int nHeigth;//We will assume that both the matrices are aquare matrices
int nWidth;
int m_size;
//PRECISION *pInput, * pFilter, * pOutput;
PRECISION *pInput, * pFilter, * pOutput;

int main()
{
    __int64 tStart, tEnd;
        clock_t t;//Creating an instance of the clock

cout<<"Enter size";
cin>>m_size;

nInputWidth=m_size;
nFilterWidth=m_size;
nHeigth=m_size;
nWidth=m_size;



pInput=new PRECISION [nWidth*nHeigth]; //dynamically create a vector (that contains all enteries of the said matrix)
pFilter=new PRECISION [nWidth*nHeigth]; //dynamically create a vector (that contains all enteries of the said matrix)




        tStart = GetTimeus64(); // Get starting time.
        t = clock();  //Starting Clock Ticks 
cout<<endl<<endl;
srand((unsigned)time(0));
/////////////////Creating The Input Matrix (in vector form)///////////////////
for (int c=0 ; c<nHeigth ; c++)
{
        for (int f=0 ; f<nWidth ;f++)
        {
                PRECISION X=100;
                random_value1= (double)rand()/((double)RAND_MAX/X);
                if (random_value1<10)
                {
                pInput[c*nWidth+f]=random_value1;
                //cout<<"    "<<'0';
                //cout<<pInput[c*nWidth+f];
                }
                else
                {
                pInput[c*nWidth+f]=random_value1;
                //cout<<"    "<<pInput[c*nWidth+f];
                }
        }
        //cout<<endl;
}
        cout<<endl<<endl;
        cout<<"************************************************************************";
        cout<<endl<<endl;
        ////////////////////////////Creating Matrix 2 (in vector form)//////////////////
for (int g=0 ; g<nHeigth ; g++)
{
        for (int h=0 ; h<nWidth ;h++)
        {
				PRECISION X=100;
                random_value2= (double)rand()/((double)RAND_MAX/X);
                if (random_value2<10)
                {
                pFilter[g*nWidth+h]=random_value2;
                //cout<<"    "<<'0';
                //cout<<e[g*cols2+h];
                }
                else
                {
                pFilter[g*nWidth+h]=random_value2;
                //cout<<"    "<<e[g*cols2+h];
                }
        }
        //cout<<endl;
}
//cout<<endl;
cout<<endl<<endl;
        cout<<"************************************************************************";
        cout<<endl<<endl;
Convolve(  pInput,  pFilter,  pOutput,  nInputWidth,  nWidth,  nHeigth, nFilterWidth);
       

t = clock() - t;        //Calculating total clicks of the clock.
        tEnd = GetTimeus64(); // Get ending time.
        // Difference between starting and ending time in seconds.
    cout << "Time taken = " << ((double)(tEnd-tStart))/(1000000.) << " seconds (High Precision)." << endl;
        cout<<"It took me "<<((double)t)/CLOCKS_PER_SEC<<" seconds (3 dp)."<<endl;

        delete[] pInput;
        delete[] pFilter;
        delete[] pOutput;

    return 0;

}


//////Convolution Function Definition///////
void Convolve(PRECISION * pInput, PRECISION * pFilter, PRECISION * pOutput,
 		 int nInputWidth, int nWidth, int nHeight, 
 		 int nFilterWidth)
{
pOutput=new PRECISION [nWidth*nHeigth];
  for (int yOut = 0; yOut < nHeight; yOut++)
  {
    const int yInTopLeft = yOut;
    for (int xOut = 0; xOut < nWidth; xOut++)
    {
     	const int xInTopLeft = xOut;
     	PRECISION sum = 0;
    	for (int r = 0; r < nFilterWidth; r++)
    	{
    		const int idxFtmp = r * nFilterWidth;
    		const int yIn = yInTopLeft + r;
    		const int idxIntmp = yIn * nInputWidth + xInTopLeft;
    		for (int c = 0; c < nFilterWidth; c++)
    		{
    			const int idxF  = idxFtmp  + c;
    			const int idxIn = idxIntmp + c; 
    			sum += pFilter[xOut*idxF+c]*pInput[xOut*idxIn+c];
    		}
    	}
    	const int idxOut = yOut * nWidth + xOut;
    	pOutput[yOut*idxOut+xOut] = sum;
    }
  }
}